package umage.figures;


import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Double;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JOptionPane;

import org.jhotdraw.draw.EllipseFigure;
import org.jhotdraw.draw.Handle;
import org.jhotdraw.draw.MoveHandle;
import org.jhotdraw.xml.DOMInput;
import org.jhotdraw.xml.DOMOutput;

@FigureInfo(icon = "PlaceFigure.png", name = "Place Figure")
public class PlaceFigure extends EllipseFigure {
	
	protected static final double PLACE_WIDTH = 50;
	protected static final double PLACE_HEIGHT = 50;
	protected static final double TOKEN_WIDTH = 7;
	protected static final double TOKEN_HEIGHT = 7;
	protected static final double TOKEN_RADIUS = 15;
	protected static final int TOKEN_LIMIT = 10;
	protected int currentTokens;
	protected int defaultTokens;
	protected boolean altered;
	
	public PlaceFigure() {
		currentTokens = 0;
		defaultTokens = 0;
		altered = false;
	}
	
	@Override
	public Collection<Handle> createHandles(int detailLevel) {
		LinkedList<Handle> handles = new LinkedList<Handle>();
        if (detailLevel == 0) {
        	MoveHandle.addMoveHandles(this, handles);
        }
        return handles;
	}
	
	@Override
	public void basicSetBounds(Double anchor, Double lead) {
		Point2D.Double a = new Point2D.Double(Math.min(anchor.x, lead.x), Math.min(anchor.y, lead.y));
		Point2D.Double b = new Point2D.Double(a.x + PLACE_WIDTH, a.y + PLACE_HEIGHT);
		
		super.basicSetBounds(a, b);
	}
	
	@Override
	public Collection<Action> getActions(Double p) {
		ArrayList<Action> actions = new ArrayList<Action>();
		actions.add(new ChangeCountAction());
		return actions;
	}
	
	@Override
	protected void drawFill(Graphics2D g) {
		super.drawFill(g);
		g.setColor(Color.BLACK);
		Rectangle2D.Double bounds = getBounds();
		Point2D.Double center = new Point2D.Double(bounds.x + (bounds.width / 2), bounds.y + (bounds.height / 2));
		if (currentTokens <= TOKEN_LIMIT) {
			double spacing = (2 * Math.PI) / currentTokens;
			for (int i = 0; i < currentTokens; i++) {
				double x = center.x + (TOKEN_RADIUS * Math.cos(spacing * i)) - (TOKEN_WIDTH / 2);
				double y = center.y + (TOKEN_RADIUS * Math.sin(spacing * i)) - (TOKEN_HEIGHT / 2);
				g.fillOval((int)x, (int)y, (int)TOKEN_WIDTH, (int)TOKEN_HEIGHT);
			}
		} else {
			String tokenString = new Integer(currentTokens).toString();
			double width = g.getFontMetrics().getStringBounds(tokenString, g).getWidth();
			g.drawString(tokenString, (int)(center.x - (width / 2)), (int)center.y);
		}
	}
	
	public int getTokenCount() {
		return currentTokens;
	}
	
	public boolean canAddTokens(int t) {
		return true;
	}
	
	public boolean addTokens(int t) {
		if (canAddTokens(t)) {
			currentTokens += t;
			altered = true;
			return true;
		}
		return false;
	}
	
	public boolean canRemoveTokens(int t) {
		return currentTokens >= t;
	}
	
	public boolean removeTokens(int t) {
		if (canRemoveTokens(t)) {
			currentTokens -= t;
			altered = true;
			return true;
		}
		return false;
	}
	
	public void reset() {
		currentTokens = defaultTokens;
		altered = false;
	}
	
	protected class ChangeCountAction extends AbstractAction {
		
		public ChangeCountAction() {
			super("Change Default Value...");
		}
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			while (true) {
				String result = JOptionPane.showInputDialog(null, "New (default) token value:", defaultTokens);
				if (result == null) break;
				try {
					Integer val = Integer.parseInt(result, 10);
					if (val > 0) {
						if (currentTokens == defaultTokens && !altered) {
							currentTokens = val;
						} else {
							JOptionPane.showMessageDialog(null, "This place has been altered by the simulation system\nThis change will take effect the next time the system is reset", "Place out-of-sync", JOptionPane.WARNING_MESSAGE);
						}
						defaultTokens = val;
						break;
					}
				} catch (Exception ex) {}
				JOptionPane.showMessageDialog(null, "Please enter a valid positive number", "Invalid Input", JOptionPane.ERROR_MESSAGE);
			}
		}
	}
	
	@Override
	public void read(DOMInput in) throws IOException {
		defaultTokens = in.getAttribute("tokens", 0);
		currentTokens = defaultTokens;
		altered = false;
		super.read(in);
	}
	
	@Override
	public void write(DOMOutput out) throws IOException {
		out.addAttribute("tokens", defaultTokens);
		super.write(out);
	}
	
	@Override
	public PlaceFigure clone() {
		PlaceFigure that = (PlaceFigure) super.clone();
		that.defaultTokens = defaultTokens;
		that.currentTokens = defaultTokens;
		that.altered = false;
		return that;
	}
	
}
